package chapter_23.security;

/**
 * Created by Administrator
 * Created time 2018/8/10 11:02.
 * 线程通信
 */
public class ThreadCommuni {

    public static void main(String[] args) {

        Stack stack = new Stack();

        /*
         下面的消费者和生产者
         所操作的是同一个堆栈对象 stack
         */

        // 生产者线程
        Thread producer = new Thread(() -> {
            char c;
            for (int i = 0; i < 10; i++) {
                // 随机产生 10 个字符
                c = (char) (Math.random() * 26 + 'A');
                // 把字符压栈
                stack.push(c);
                // 打印字符
                System.out.println("生产: " + c);
                try {
                    // 每产生一个字符线程就休眠
                    Thread.sleep((int) (Math.random() * 1000));
                } catch (InterruptedException e) {
                    System.out.println("线程执行异常!");
                }
            }
        });

        // 消费者线程
        Thread consumer = new Thread(() -> {
            char c;
            for (int i = 0; i < 10; i++) {
                // 从堆栈中读取字符
                c = stack.pop();
                // 打印字符
                System.out.println("消费: " + c);
                try {
                    // 每产生一个字符线程就休眠
                    Thread.sleep((int) (Math.random() * 1000));
                } catch (InterruptedException e) {
                    System.out.println("线程执行异常!");
                }
            }
        });

        // 启动生产者线程
        producer.start();
        // 启动消费者线程
        consumer.start();
    }
}

// 堆栈类
class Stack {

    // 堆栈指针初始值为 0
    private int pointer = 0;
    // 堆栈有5个字符的空间
    private char[] chars = new char[5];

    // 入栈方法, 加上互斥锁
    public synchronized void push(char c) {
        // 堆栈已满, 不能出栈
        while (pointer == chars.length) {
            try {
                // 等待其他线程将数据出栈
                this.wait();
            } catch (InterruptedException e) {
                System.out.println("线程运行异常!");
            }
        }
        // 通知其他线程将数据出栈
        this.notify();
        // 数据压栈
        chars[pointer] = c;
        // 指针向上移动
        pointer++;
    }

    // 出栈方法, 加上互斥锁
    public synchronized char pop() {
        // 堆栈无数据, 不能出栈
        while (pointer == 0) {
            try {
                // 等待其他线程将数据压栈
                this.wait();
            } catch (InterruptedException e) {
                System.out.println("线程运行异常!");
            }
        }
        // 通知其他线程压栈
        this.notify();
        // 指针向下移动
        pointer--;
        // 数据出栈
        return chars[pointer];
    }
}
